'''
Created on 26/05/2011

@author: Hagut
'''

from game_agent import GameAgent
from alpha_beta_improved import AlphaBetaSearchImproved
from our_adds.utils import PriorityQueue
from time import clock
from general import get1Successor

INFINITY = 1.0e400
SAFE_EXT = 0.001
NO_LIMIT = -1

' ~~~~~~taken from AlphaBetaAgent for refernece, should be changed to our agent ~~~~~~~'
 
class SuperAgent(GameAgent):
    '''
    This is an interface for a Game Playing Agent.
    '''
    def move(self, game_state):
        '''
        This is the method called by the runner of this agent.
        It includes the code that decides the next move.
        
        @param game_state: The current game state.
        @return: The GameAction that the agent will execute in its next move.
        '''
#        return self.search(game_state, self.turn_time_limit)
        stime = clock()
        res =  self.search(game_state, self.turn_time_limit)
        print "turn time",clock()-stime
        return res
    
    def setup(self, player, game_state, turn_time_limit, setup_time_limit):
        '''
        This is method is called once at the beginning of the game, 
        and enables the agent to prepare for things to come.
        
        @param player: Your player.
        @param game_state: The initial game state.
        @param turn_time_limit: The time that will be allocated for each turn.
        @param setup_time_limit: The time limit for setting up this agent.
        '''
        self.player = player
        self.turn_time_limit = turn_time_limit
        u = lambda state: self.utility(state)
        self.initSearch(2)
        #self.alphaBeta = AlphaBetaSearchImproved(self.player, 3, u, self)

    def utility(self, state):
        winner = state.getWinner()
        if winner is None:
            return 0
        elif winner == self.player:
            return 1
        else:
            return -1  
        
    def getSuccImproved(self, gameState):
        successors = PriorityQueue()
        for action, value in gameState.getSuccessors().items():
            #print "get successors action", action
            #print "get successors value", 
            #print value
            successors.append((action, value))
        return successors, None     
    
    
    ' !!!!!!!!!!!!!!!!!!!!!! '
    ' search function'
    def initSearch(self, max_depth):
        self.max_depth = max_depth
    
    def search(self, current_state, time2run):
        '''
        Search game to determine best action; use alpha-beta pruning.
        
        @param current_state: The current game state to start the search from.
        '''
        
        ' set start time '
        initTime = clock()
        safe_time2run = float(time2run) - SAFE_EXT
        best_value = -INFINITY
        ''' I think we should find something better here.........'''
        (action,best_action) = get1Successor(current_state) 
        if (clock() - initTime < safe_time2run):
            ' ~~ changed here : use priority queue '
            res = self.getSuccImproved(current_state)
            successors = res[0]
        else:
            return best_action
        
        while ((len(successors) != 0) and (clock() - initTime < safe_time2run)):
            ' remove one item from the queue '
            (action, state) = successors.pop()
            ' for case there is no time to return nothing'
            #for action, state in current_state.getSuccessors().items():
            value_fn = self._getValueFn(state)
            value = value_fn(state, best_value, INFINITY, 1, initTime, safe_time2run)
            if value > best_value:
                best_value = value
                best_action = action
        return best_action
    
    def _getValueFn(self, state):
        if state.getCurrentPlayer() == self.player:
            return self._maxValue
        else:
            return self._minValue
    
    def _cutoffTest(self, state, depth):
        return depth >= self.max_depth or (state.getWinner() is not None)
    
    def _maxValue(self, state, alpha, beta, depth, initTime, safe_time2run):
        if self._cutoffTest(state, depth):
            return self.utility(state)
        'TODO add time here and in the following code'        
        value = -INFINITY
        if (clock() - initTime < safe_time2run):
            ' ~~ changed here : use priority queue '
            res = self.getSuccImproved(state)
            successors = res[0]
        else:
            return value
        while ((len(successors) != 0) and (clock() - initTime < safe_time2run)):
            ' remove one item from the queue '
            (action, successor) = successors.pop()
            #for successor in successors.values():s
            value_fn = self._getValueFn(successor)
            value = max(value, value_fn(successor, alpha, beta, depth + 1, initTime, safe_time2run))
            if value >= beta:
                return value
            alpha = max(alpha, value)
        
        return value
    
    def _minValue(self, state, alpha, beta, depth, initTime, safe_time2run):
        if self._cutoffTest(state, depth):
            return self.utility(state)
        
        value = INFINITY
        if (clock() - initTime < safe_time2run):
            ' ~~ changed here : use priority queue '
            res = self.getSuccImproved(state)
            successors = res[0]
        else:
            return value
        while ((len(successors) != 0) and (clock() - initTime < safe_time2run)):
            ' remove one item from the queue '
            res = successors.pop()
            action = res[0]
            successor = res[1]
            #for successor in successors.values():
            value_fn = self._getValueFn(successor)
            value = min(value, value_fn(successor, alpha, beta, depth + 1, initTime, safe_time2run))
            if value <= alpha:
                return value
            beta = min(beta, value)
        
        return value
